[/
  Copyright 2011 - 2020 John Maddock.
  Copyright 2013 - 2019 Paul A. Bristow.
  Copyright 2013 Christopher Kormanyos.

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE_1_0.txt or copy at
  http://www.boost.org/LICENSE_1_0.txt).
]

[section:number number]

[h4 Synopsis]

   namespace boost{ namespace multiprecision{

   enum expression_template_option { et_on = 1, et_off = 0 };

   template <class Backend> struct expression_template_default
   { static const expression_template_option value = et_on; };

   template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
   class number
   {
   public:
      typedef          Backend                          backend_type;
      typedef typename component_type<self_type>::type  value_type;

      number();
      number(see-below);
      number& operator=(see-below);
      number& assign(see-below);

      // Member operators
      number& operator+=(const ``['see-below]``&);
      number& operator-=(const ``['see-below]``&);
      number& operator*=(const ``['see-below]``&);
      number& operator/=(const ``['see-below]``&);
      number& operator++();
      number& operator--();
      number  operator++(int);
      number  operator--(int);

      number& operator%=(const ``['see-below]``&);
      number& operator&=(const ``['see-below]``&);
      number& operator|=(const ``['see-below]``&);
      number& operator^=(const ``['see-below]``&);
      number& operator<<=(const ``['integer-type]``&);
      number& operator>>=(const ``['integer-type]``&);

      // Use in Boolean context:
      operator ``['convertible-to-bool-type]``()const;
      // swap:
      void swap(number& other);
      // Sign:
      bool is_zero()const;
      int sign()const;
      // string conversion:
      std::string str()const;
      // Generic conversion mechanism
      template <class T>
      T convert_to()const;
      template <class T>
      explicit operator T ()const;
      // precision control:
      static unsigned default_precision();
      static void default_precision(unsigned digits10);
      unsigned precision()const;
      void precision(unsigned digits10);
      // Comparison:
      int compare(const number<Backend>& o)const;
      template <class V>
      typename boost::enable_if<boost::is_convertible<V, number<Backend, ExpressionTemplates> >, int>::type
         compare(const V& o)const;
      // real and imaginary parts:
      value_type real()const;
      value_type imag()const;
      template <class T>
      void real(const T& val);
      template <class T>
      void imag(const T& val);
      // Access to the underlying implementation:
      Backend& backend();
      const Backend& backend()const;
   };

   // Non member operators:
   ``['unmentionable-expression-template-type]`` operator+(const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator-(const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator+(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator-(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator*(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator/(const ``['see-below]``&, const ``['see-below]``&);
   // Integer only operations:
   ``['unmentionable-expression-template-type]`` operator%(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator&(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator|(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator^(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator<<(const ``['see-below]``&, const ``['integer-type]``&);
   ``['unmentionable-expression-template-type]`` operator>>(const ``['see-below]``&, const ``['integer-type]``&);
   // Comparison operators:
   bool operator==(const ``['see-below]``&, const ``['see-below]``&);
   bool operator!=(const ``['see-below]``&, const ``['see-below]``&);
   bool operator< (const ``['see-below]``&, const ``['see-below]``&);
   bool operator> (const ``['see-below]``&, const ``['see-below]``&);
   bool operator<=(const ``['see-below]``&, const ``['see-below]``&);
   bool operator>=(const ``['see-below]``&, const ``['see-below]``&);

   // Swap:
   template <class Backend, expression_template_option ExpressionTemplates>
   void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b);

   // iostream support:
   template <class Backend, expression_template_option ExpressionTemplates>
   std::ostream& operator << (std::ostream& os, const number<Backend, ExpressionTemplates>& r);
   std::ostream& operator << (std::ostream& os, const ``['unmentionable-expression-template-type]``& r);
   template <class Backend, expression_template_option ExpressionTemplates>
   std::istream& operator >> (std::istream& is, number<Backend, ExpressionTemplates>& r);

   // Arithmetic with a higher precision result:
   template <class ResultType, class Source1 class Source2>
   ResultType& add(ResultType& result, const Source1& a, const Source2& b);
   template <class ResultType, class Source1 class Source2>
   ResultType& subtract(ResultType& result, const Source1& a, const Source2& b);
   template <class ResultType, class Source1 class Source2>
   ResultType& multiply(ResultType& result, const Source1& a, const Source2& b);

   // min and max overloads:
   ``['number]``                                    min    (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['number]``                                    max    (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);

   // C99 Non-member function standard library support:
   ``['unmentionable-expression-template-type]``    abs        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    acos       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    acosh      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    asin       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    asinh      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    atan       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    atan2      (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['number]``                                    atanh      (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    cbrt       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    ceil       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    copysign   (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    cos        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    cosh       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    erf        (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    erfc       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    exp        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    exp2       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    expm1      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fabs       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fdim       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    floor      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fma        (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fmin       (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fmax       (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fmod       (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    frexp      (const ``['number-or-expression-template-type]``&, ``['integer-type]``*);
   ``['unmentionable-expression-template-type]``    hypot      (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['integer-type]``                              ilogb      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    ldexp      (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
   ``['number]``                                    lgamma     (const ``['number-or-expression-template-type]``&);
   long long                                 llrint     (const ``['number-or-expression-template-type]``&);
   long long                                 llround    (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    log        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    log2       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    log10      (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    log1p      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    logb       (const ``['number-or-expression-template-type]``&);
   long                                      lrint      (const ``['number-or-expression-template-type]``&);
   long                                      lround     (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    modf       (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    nearbyint  (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    nextafter  (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['number]``                                    nexttoward (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    pow        (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    remainder  (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    remquo     (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&, int*);
   ``['unmentionable-expression-template-type]``    rint       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    round      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    scalbn     (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
   ``['unmentionable-expression-template-type]``    scalbln    (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
   ``['unmentionable-expression-template-type]``    sin        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    sinh       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    sqrt       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    tan        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    tanh       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    tgamma     (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    trunc      (const ``['number-or-expression-template-type]``&);

   int                                       fpclassify (const ``['number-or-expression-template-type]``&);
   bool                                      isfinite   (const ``['number-or-expression-template-type]``&);
   bool                                      isinf      (const ``['number-or-expression-template-type]``&);
   bool                                      isnan      (const ``['number-or-expression-template-type]``&);
   bool                                      isnormal   (const ``['number-or-expression-template-type]``&);
   int                                       signbit    (const ``['number-or-expression-template-type]``&);

   bool                                      isgreater  (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      isgreaterequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      isless     (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      islessequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-typearea]``&);
   bool                                      islessgreater(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      isunordered(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   // Complex number functions:
   ``['number<...>::value_type]``                   real  (const ``['number-or-expression-template-type]``&);
   ``['number<...>::value_type]``                   imag  (const ``['number-or-expression-template-type]``&);
   ``['number<...>::value_type]``                   abs   (const ``['number-or-expression-template-type]``&);
   ``['number<...>::value_type]``                   arg   (const ``['number-or-expression-template-type]``&);
   ``['number<...>::value_type]``                   norm  (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    conj  (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    proj  (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    polar (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   // Misc other common C library functions:
   ``['unmentionable-expression-template-type]``    itrunc (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    ltrunc (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    lltrunc(const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    iround (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    changesign(const ``['number-or-expression-template-type]``&);
   ``['number]``                                    copysign(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);

   // Traits support:
   template <class T>
   struct component_type;
   template <class T>
   struct number_category;
   template <class T>
   struct is_number;
   template <class T>
   struct is_number_expression;

   // Integer specific functions:
   ``['unmentionable-expression-template-type]``    gcd(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    lcm(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    pow(const ``['number-or-expression-template-type]``&, unsigned);
   ``['unmentionable-expression-template-type]``    powm(const ``['number-or-expression-template-type]``& b, const ``['number-or-expression-template-type]``& p, const ``['number-or-expression-template-type]``& m);
   ``['unmentionable-expression-template-type]``    sqrt(const ``['number-or-expression-template-type]``&);
   template <class Backend, expression_template_option ExpressionTemplates>
   number<Backend, EXpressionTemplates>      sqrt(const ``['number-or-expression-template-type]``&, number<Backend, EXpressionTemplates>&);
   template <class Backend, expression_template_option ExpressionTemplates>
   void divide_qr(const ``['number-or-expression-template-type]``& x, const ``['number-or-expression-template-type]``& y,
                  number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r);
   template <class Integer>
   Integer integer_modulus(const ``['number-or-expression-template-type]``& x, Integer val);
   unsigned lsb(const ``['number-or-expression-template-type]``& x);
   unsigned msb(const ``['number-or-expression-template-type]``& x);
   template <class Backend, class ExpressionTemplates>
   bool bit_test(const number<Backend, ExpressionTemplates>& val, unsigned index);
   template <class Backend, class ExpressionTemplates>
   number<Backend, ExpressionTemplates>& bit_set(number<Backend, ExpressionTemplates>& val, unsigned index);
   template <class Backend, class ExpressionTemplates>
   number<Backend, ExpressionTemplates>& bit_unset(number<Backend, ExpressionTemplates>& val, unsigned index);
   template <class Backend, class ExpressionTemplates>
   number<Backend, ExpressionTemplates>& bit_flip(number<Backend, ExpressionTemplates>& val, unsigned index);
   template <class Engine>
   bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials, Engine& gen);
   bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials);

   // Rational number support:
   typename component_type<``['number-or-expression-template-type]``>::type numerator  (const ``['number-or-expression-template-type]``&);
   typename component_type<``['number-or-expression-template-type]``>::type denominator(const ``['number-or-expression-template-type]``&);

   }} // namespaces

   namespace boost{ namespace math{

   // Boost.Math interoperability functions:
   int                                              fpclassify     (const ``['number-or-expression-template-type]``&, int);
   bool                                             isfinite       (const ``['number-or-expression-template-type]``&, int);
   bool                                             isnan          (const ``['number-or-expression-template-type]``&, int);
   bool                                             isinf          (const ``['number-or-expression-template-type]``&, int);
   bool                                             isnormal       (const ``['number-or-expression-template-type]``&, int);

   }} // namespaces

   // numeric_limits support:
   namespace std{

   template <class Backend, expression_template_option ExpressionTemplates>
   struct numeric_limits<nil::crypto3::multiprecision<Backend, ExpressionTemplates> >
   {
      /* Usual members here */
   };

   }

[h4 Description]

   enum expression_template_option { et_on = 1, et_off = 0 };

This enumerated type is used to specify whether expression templates are turned on (et_on) or turned off (et_off).

   template <class Backend> struct expression_template_default
   { static const expression_template_option value = et_on; };

This traits class specifies the default expression template option to be used with a particular Backend type.
It defaults to `et_on`.

   template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
   class number;

Class `number` has two template arguments:

[variablelist
[[Backend][The actual arithmetic back-end that does all the work.]]
[[ExpressionTemplates][A Boolean value: when `et_on`, then expression templates are enabled, otherwise when set to `et_off` they are disabled.
   The default for this parameter is computed via the traits class `expression_template_default` whose member `value` defaults to `et_on` unless
   the traits class is specialized for a particular backend.]]
]

   number();
   number(see-below);
   number& operator=(see-below);
   number& assign(see-below);

Type `number` is default constructible, and both copy constructible and assignable from:

* Itself.
* An expression template which is the result of one of the arithmetic operators.
* Any __fundamental arithmetic type, as long as the result would not be lossy (for example float to integer conversion).
* Any type that the Backend is implicitly constructible or assignable from.
* An rvalue reference to another `number`.  Move-semantics are used for construction if the backend also
supports rvalue reference construction.  In the case of assignment, move semantics are always supported
when the argument is an rvalue reference irrespective of the backend.
* Any type in the same family, as long as no loss of precision is involved.  For example from `int128_t` to `int256_t`,
or `cpp_dec_float_50` to `cpp_dec_float_100`.

Type `number` is explicitly constructible from:

* Any type mentioned above.
* A `std::string` or any type which is convertible to `const char*`.
* Any arithmetic type (including those that would result in lossy conversions).
* Any type in the same family, including those that result in loss of precision.
* Any type that the Backend is explicitly constructible from.
* Any pair of types for which a generic interconversion exists: that is from integer to integer, integer
to rational, integer to float, rational to rational, rational to float, or float to float.

The assign member function is available for any type for which an explicit converting constructor exists.
It is intended to be used where a temporary generated from an explicit assignment would be expensive, for example:

   mpfr_float_50    f50;
   mpfr_float_100   f100;

   f50 = static_cast<mpfr_float_50>(f100);  // explicit cast create a temporary
   f50.assign(f100);                        // explicit call to assign create no temporary

In addition, if the type has multiple components (for example rational or complex number types), then there is a
two argument constructor:

   number(arg1, arg2);

Where the two args must either be arithmetic types, or types that are convertible to the two components of `this`.

Finally, when the type has a variable precision, then there are constructors:

   number(arg1, precision);
   number(arg1, arg2, precision);

Where `precision` is an unsigned value, the 2 arg version is active for scalar types and/or copy-construction with specific precision, and the 3-arg version for complex types.

Likewise `assign` has a 2-arg overloaded, with the second argument being the precision.

      number& operator+=(const ``['see-below]``&);
      number& operator-=(const ``['see-below]``&);
      number& operator*=(const ``['see-below]``&);
      number& operator/=(const ``['see-below]``&);
      number& operator++();
      number& operator--();
      number  operator++(int);
      number  operator--(int);
      // Integer only operations:
      number& operator%=(const ``['see-below]``&);
      number& operator&=(const ``['see-below]``&);
      number& operator|=(const ``['see-below]``&);
      number& operator^=(const ``['see-below]``&);
      number& operator<<=(const ``['integer-type]``&);
      number& operator>>=(const ``['integer-type]``&);

These operators all take their usual arithmetic meanings.

The arguments to these operators is either:

* Another `number<Backend, ExpressionTemplates>`.
* An expression template derived from `number<Backend>`.
* Any type implicitly convertible to `number<Backend, ExpressionTemplates>`, including some other instance of class `number`.

For the left and right shift operations, the argument must be a __fundamental
integer type with a positive value (negative values result in a `std::runtime_error` being thrown).

      operator ``['convertible-to-bool-type]``()const;

Returns an ['unmentionable-type] that is usable in Boolean contexts (this allows `number` to be used in any
Boolean context - if statements, conditional statements, or as an argument to a logical operator - without
type `number` being convertible to type `bool`.

This operator also enables the use of `number` with any of the following operators:
`!`, `||`, `&&` and `?:`.

      void swap(number& other);

Swaps `*this` with `other`.

      bool is_zero()const;

Returns `true` is `*this` is zero, otherwise `false`.

      int sign()const;

Returns a value less than zero if `*this` is negative, a value greater than zero if `*this` is positive, and zero
if `*this` is zero.

      std::string str(unsigned precision, bool scientific = true)const;

Returns the number formatted as a string, with at least /precision/ digits, and in scientific format
if /scientific/ is true.

      template <class T>
      T convert_to()const;

      template <class T>
      explicit operator T ()const;

Provides a generic conversion mechanism to convert `*this` to type `T`.  Type `T` may be any arithmetic type.
Optionally other types may also be supported by specific `Backend` types.


      static unsigned default_precision();
      static void default_precision(unsigned digits10);
      unsigned precision()const;
      void precision(unsigned digits10);

These functions are only available if the Backend template parameter supports runtime changes to precision.  They get and set
the default precision and the precision of `*this` respectively.

      int compare(const number<Backend, ExpressionTemplates>& o)const;
      template <class V>
      typename boost::enable_if<boost::is_convertible<V, number<Backend, ExpressionTemplates> >, int>::type
         compare(const V& other)const;

Returns:

* A value less that 0 for `*this < other`
* A value greater that 0 for `*this > other`
* Zero for `*this == other`

      value_type real()const;
      value_type imag()const;

These return the real and imaginary parts respectively.  If the number is not a complex type, then the imaginary part is always zero.

      template <class T>
      void real(const T& val);
      template <class T>
      void imag(const T& val);

These set the real and imaginary parts respectively of the number.  If the number is not a complex type, then setting the real part
is equivalent to assignment, and attempting to set the imaginary part will result in a compile time error.

      Backend& backend();
      const Backend& backend()const;

Returns the underlying back-end instance used by `*this`.

[h4 Non-member operators]

   // Non member operators:
   ``['unmentionable-expression-template-type]`` operator+(const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator-(const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator+(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator-(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator*(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator/(const ``['see-below]``&, const ``['see-below]``&);
   // Integer only operations:
   ``['unmentionable-expression-template-type]`` operator%(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator&(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator|(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator^(const ``['see-below]``&, const ``['see-below]``&);
   ``['unmentionable-expression-template-type]`` operator<<(const ``['see-below]``&, const ``['integer-type]``&);
   ``['unmentionable-expression-template-type]`` operator>>(const ``['see-below]``&, const ``['integer-type]``&);
   // Comparison operators:
   bool operator==(const ``['see-below]``&, const ``['see-below]``&);
   bool operator!=(const ``['see-below]``&, const ``['see-below]``&);
   bool operator< (const ``['see-below]``&, const ``['see-below]``&);
   bool operator> (const ``['see-below]``&, const ``['see-below]``&);
   bool operator<=(const ``['see-below]``&, const ``['see-below]``&);
   bool operator>=(const ``['see-below]``&, const ``['see-below]``&);

These operators all take their usual arithmetic meanings.

The arguments to these functions must contain at least one of the following:

* A `number`.
* An expression template type derived from `number`.
* Any type for which `number` has an implicit constructor - for example a __fundamental arithmetic type.

The return type of these operators is either:

* An ['unmentionable-type] expression template type when `ExpressionTemplates` is `true`.
* Type `number<Backend, et_off>` when `ExpressionTemplates` is `false`.
* Type `bool` if the operator is a comparison operator.

Finally note that the second argument to the left and right shift operations must be a __fundamental integer type,
and that the argument must be positive (negative arguments result in a `std::runtime_error` being thrown).

[h4 swap]

   template <class Backend, ExpressionTemplates>
   void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b);

Swaps `a` and `b`.

[h4 Iostream Support]

   template <class Backend, expression_template_option ExpressionTemplates>
   std::ostream& operator << (std::ostream& os, const number<Backend, ExpressionTemplates>& r);
   template <class Unspecified...>
   std::ostream& operator << (std::ostream& os, const unmentionable-expression-template& r);
   template <class Backend, expression_template_option ExpressionTemplates>
   inline std::istream& operator >> (std::istream& is, number<Backend, ExpressionTemplates>& r)

These operators provided formatted input-output operations on `number` types, and expression templates derived from them.

It's down to the back-end type to actually implement string conversion.  However, the back-ends provided with
this library support all of the iostream formatting flags, field width and precision settings.

[h4 Arithmetic with a higher precision result]

   template <class ResultType, class Source1 class Source2>
   ResultType& add(ResultType& result, const Source1& a, const Source2& b);

   template <class ResultType, class Source1 class Source2>
   ResultType& subtract(ResultType& result, const Source1& a, const Source2& b);

   template <class ResultType, class Source1 class Source2>
   ResultType& multiply(ResultType& result, const Source1& a, const Source2& b);

These functions apply the named operator to the arguments ['a] and ['b] and store the
result in ['result], returning ['result].  In all cases they behave "as if"
arguments ['a] and ['b] were first promoted to type `ResultType` before applying the
operator, though particular backends may well avoid that step by way of an optimization.

The type `ResultType` must be an instance of class `number`, and the types `Source1` and `Source2`
may be either instances of class `number` or native integer types.  The latter is an optimization
that allows arithmetic to be performed on native integer types producing an extended precision result.

[h4 Non-member standard library function support]

   ``['unmentionable-expression-template-type]``    abs        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    acos       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    acosh      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    asin       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    asinh      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    atan       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    atan2      (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['number]``                                    atanh      (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    cbrt       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    ceil       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    copysign   (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    cos        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    cosh       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    erf        (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    erfc       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    exp        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    exp2       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    expm1      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fabs       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fdim       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    floor      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fma        (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fmin       (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fmax       (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    fmod       (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    frexp      (const ``['number-or-expression-template-type]``&, ``['integer-type]``*);
   ``['unmentionable-expression-template-type]``    hypot      (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['integer-type]``                              ilogb      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    ldexp      (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
   ``['number]``                                    lgamma     (const ``['number-or-expression-template-type]``&);
   long long                                 llrint     (const ``['number-or-expression-template-type]``&);
   long long                                 llround    (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    log        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    log2       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    log10      (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    log1p      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    logb       (const ``['number-or-expression-template-type]``&);
   long                                      lrint      (const ``['number-or-expression-template-type]``&);
   long                                      lround     (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    modf       (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    nearbyint  (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    nextafter  (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['number]``                                    nexttoward (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    pow        (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    remainder  (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    remquo     (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&, int*);
   ``['unmentionable-expression-template-type]``    rint       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    round      (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    scalbn     (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
   ``['unmentionable-expression-template-type]``    scalbln    (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
   ``['unmentionable-expression-template-type]``    sin        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    sinh       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    sqrt       (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    tan        (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    tanh       (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    tgamma     (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    trunc      (const ``['number-or-expression-template-type]``&);

   int                                       fpclassify (const ``['number-or-expression-template-type]``&);
   bool                                      isfinite   (const ``['number-or-expression-template-type]``&);
   bool                                      isinf      (const ``['number-or-expression-template-type]``&);
   bool                                      isnan      (const ``['number-or-expression-template-type]``&);
   bool                                      isnormal   (const ``['number-or-expression-template-type]``&);
   int                                       signbit    (const ``['number-or-expression-template-type]``&);

   bool                                      isgreater  (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      isgreaterequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      isless     (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      islessequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      islessgreater(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
   bool                                      isunordered(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);

These functions all behave exactly as their standard library C++11 counterparts do: their argument is either an instance of `number` or
an expression template derived from it; If the argument is of type `number<Backend, et_off>` then that is also the return type,
otherwise the return type is an expression template unless otherwise stated.

The integer type arguments to `ldexp`, `frexp`, `scalbn` and `ilogb` may be either type `int`, or the actual
type of the exponent of the number type.

Complex number types support the following functions:

   // Complex number functions:
   ``['number<...>::value_type]``                   real  (const ``['number-or-expression-template-type]``&);
   ``['number<...>::value_type]``                   imag  (const ``['number-or-expression-template-type]``&);
   ``['number<...>::value_type]``                   abs   (const ``['number-or-expression-template-type]``&);
   ``['number<...>::value_type]``                   arg   (const ``['number-or-expression-template-type]``&);
   ``['number<...>::value_type]``                   norm  (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    conj  (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    proj  (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    polar (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);

In addition the functions `real`, `imag`, `arg`, `norm`, `conj` and `proj` are overloaded for scalar (ie non-complex) types in the same
manner as `<complex>` and treat the argument as a value whose imaginary part is zero.

There are also some functions implemented for compatibility with the Boost.Math functions of the same name:

   ``['unmentionable-expression-template-type]``    itrunc (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    ltrunc (const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    lltrunc(const ``['number-or-expression-template-type]``&);
   ``['unmentionable-expression-template-type]``    iround (const ``['number-or-expression-template-type]``&);
   ``['number]``                                    changesign(const ``['number-or-expression-template-type]``&);
   ``['number]``                                    copysign(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);

All these functions are normally implemented by the Backend type.  However, default versions are provided for Backend types that
don't have native support for these functions.  Please note however, that this default support requires the precision of the type
to be a compile time constant - this means for example that the [gmp] MPF Backend will not work with these functions when that type is
used at variable precision.

Also note that with the exception of `abs` that these functions can only be used with floating-point Backend types (if any other types
such as fixed precision or complex types are added to the library later, then these functions may be extended to support those number types).

The precision of these functions is generally determined by the backend implementation.  For example the precision
of these functions when used with __mpfr_float_backend is determined entirely by [mpfr].  When these functions use our own
implementations, the accuracy of the transcendental functions is generally a few epsilon.  Note however, that the trigonometrical
functions incur the usual accuracy loss when reducing arguments by large multiples of [pi].  Also note that both __mpf_float
and __cpp_dec_float have a number of guard digits beyond their stated precision, so the error rates listed for these
are in some sense artificially low.

The following table shows the error rates we observe for these functions with various backend types, functions not listed
here are exact (tested on Win32 with VC++10, MPFR-3.0.0, MPIR-2.1.1):

[table
[[Function][mpfr_float_50][mpf_float_50][cpp_dec_float_50]]
[[sqrt][1eps][0eps][0eps]]
[[exp][1eps][0eps][0eps]]
[[log][1eps][0eps][0eps]]
[[log10][1eps][0eps][0eps]]
[[cos][700eps][0eps][0eps]]
[[sin][1eps][0eps][0eps]]
[[tan][0eps][0eps][0eps]]
[[acos][0eps][0eps][0eps]]
[[asin][0eps][0eps][0eps]]
[[atan][1eps][0eps][0eps]]
[[cosh][1045eps[footnote It's likely that the inherent error in the input values to our test cases are to blame here.]][0eps][0eps]]
[[sinh][2eps][0eps][0eps]]
[[tanh][1eps][0eps][0eps]]
[[pow][0eps][4eps][3eps]]
[[atan2][1eps][0eps][0eps]]
]
[h4 Traits Class Support]

   template <class T>
   struct component_type;

If this is a type with multiple components (for example rational or complex types), then this trait has a single member
`type` that is the type of those components.

   template <class T>
   struct number_category;

A traits class that inherits from `boost::mpl::int_<N>` where `N` is one of the enumerated values `number_kind_integer`, `number_kind_floating_point`,
`number_kind_rational`, `number_kind_fixed_point`, or `number_kind_unknown`.  This traits class is specialized for any type that has
`std::numeric_limits` support as well as for classes in this library: which means it can be used for generic code that must work
with __fundamental arithmetic types as well as multiprecision ones.

   template <class T>
   struct is_number;

A traits class that inherits from `boost::mpl::true_` if T is an instance of `number<>`, otherwise from `boost::mpl::false_`.

   template <class T>
   struct is_number_expression;

A traits class that inherits from `boost::mpl::true_` if T is an expression template type derived from `number<>`, otherwise from `boost::mpl::false_`.


[h4 Integer functions]

In addition to functioning with types from this library, these functions are also overloaded for __fundamental integer
types if you include `<boost/multiprecision/integer.hpp>`.  Further, when used with fixed precision types (whether
__fundamental integers or multiprecision ones), the functions will promote to a wider type internally when the algorithm
requires it.  Versions overloaded for __fundamental integer types return that integer type rather than an expression
template.

   ``['unmentionable-expression-template-type]``    gcd(const ``['number-or-expression-template-type]``& a, const ``['number-or-expression-template-type]``& b);

Returns the largest integer `x` that divides both `a` and `b`.

   ``['unmentionable-expression-template-type]``    lcm(const ``['number-or-expression-template-type]``& a, const ``['number-or-expression-template-type]``& b);

Returns the smallest integer `x` that is divisible by both `a` and `b`.

   ``['unmentionable-expression-template-type]``    pow(const ``['number-or-expression-template-type]``& b, unsigned p);

Returns ['b[super p]] as an expression template.  Note that this function should be used with extreme care as the result can grow so
large as to take "effectively forever" to compute, or else simply run the host machine out of memory.  This is the one function in
this category that is not overloaded for __fundamental integer types, further, it's probably not a good idea to use it with
fixed precision `cpp_int`'s either.

   ``['unmentionable-expression-template-type]``    powm(const ``['number-or-expression-template-type]``& b, const ``['number-or-expression-template-type]``& p, const ``['number-or-expression-template-type]``& m);

Returns ['b[super p] mod m] as an expression template.  Fixed precision types are promoted internally to ensure accuracy.

   ``['unmentionable-expression-template-type]``    sqrt(const ``['number-or-expression-template-type]``& a);

Returns the largest integer `x` such that `x * x < a`.

   template <class Backend, expression_template_option ExpressionTemplates>
   number<Backend, EXpressionTemplates>      sqrt(const ``['number-or-expression-template-type]``& a, number<Backend, EXpressionTemplates>& r);

Returns the largest integer `x` such that `x * x < a`, and sets the remainder `r` such that `r = a - x * x`.

   template <class Backend, expression_template_option ExpressionTemplates>
   void divide_qr(const ``['number-or-expression-template-type]``& x, const ``['number-or-expression-template-type]``& y,
                  number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r);

Divides x by y and returns both the quotient and remainder.  After the call `q = x / y` and `r = x % y`.

   template <class Integer>
   Integer integer_modulus(const ``['number-or-expression-template-type]``& x, Integer val);

Returns the absolute value of `x % val`.

   unsigned lsb(const ``['number-or-expression-template-type]``& x);

Returns the (zero-based) index of the least significant bit that is set to 1.

Throws a `std::range_error` if the argument is <= 0.

   unsigned msb(const ``['number-or-expression-template-type]``& x);

Returns the (zero-based) index of the most significant bit.

Throws a `std::range_error` if the argument is <= 0.

   template <class Backend, class ExpressionTemplates>
   bool bit_test(const number<Backend, ExpressionTemplates>& val, unsigned index);

Returns `true` if the bit at /index/ in /val/ is set.

   template <class Backend, class ExpressionTemplates>
   number<Backend, ExpressionTemplates>& bit_set(number<Backend, ExpressionTemplates>& val, unsigned index);

Sets the bit at /index/ in /val/, and returns /val/.

   template <class Backend, class ExpressionTemplates>
   number<Backend, ExpressionTemplates>& bit_unset(number<Backend, ExpressionTemplates>& val, unsigned index);

Unsets the bit at /index/ in /val/, and returns /val/.

   template <class Backend, class ExpressionTemplates>
   number<Backend, ExpressionTemplates>& bit_flip(number<Backend, ExpressionTemplates>& val, unsigned index);

Flips the bit at /index/ in /val/, and returns /val/.

   template <class Engine>
   bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials, Engine& gen);
   bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials);

Tests to see if the number /n/ is probably prime - the test excludes the vast majority of composite numbers
by excluding small prime factors and performing a single Fermat test.  Then performs /trials/ Miller-Rabin
tests.  Returns `false` if /n/ is definitely composite, or `true` if /n/ is probably prime with the
probability of it being composite less than 0.25^trials.  Fixed precision types are promoted internally
to ensure accuracy.

[h4 Rational Number Functions]

   typename component_type<``['number-or-expression-template-type]``>::type numerator  (const ``['number-or-expression-template-type]``&);
   typename component_type<``['number-or-expression-template-type]``>::type denominator(const ``['number-or-expression-template-type]``&);

These functions return the numerator and denominator of a rational number respectively.

[h4 Boost.Math Interoperability Support]

   namespace boost{ namespace math{

   int  fpclassify     (const ``['number-or-expression-template-type]``&, int);
   bool isfinite       (const ``['number-or-expression-template-type]``&, int);
   bool isnan          (const ``['number-or-expression-template-type]``&, int);
   bool isinf          (const ``['number-or-expression-template-type]``&, int);
   bool isnormal       (const ``['number-or-expression-template-type]``&, int);

   }} // namespaces

These floating-point classification functions behave exactly as their Boost.Math equivalents.

Other Boost.Math functions and templates may also be
specialized or overloaded to ensure interoperability.

[h4 std::numeric_limits support]

   namespace std{

   template <class Backend, ExpressionTemplates>
   struct numeric_limits<nil::crypto3::multiprecision<Backend, ExpressionTemplates> >
   {
      /* Usual members here */
   };

   }

Class template `std::numeric_limits` is specialized for all instantiations of `number` whose precision is known at compile time, plus those
types whose precision is unlimited (though it is much less useful in those cases).  It is not specialized for types
whose precision can vary at compile time (such as `mpf_float`).

[endsect]
